/**
 * Copyright (c) 2012-2014, Yang Yang <cntototo@gmail.com>
 *
 * This software may be distributed under the terms of the New BSD License.
 * See README for more details.
 */

#include "log.h"

#include "include.h"

int log_level = DEFAULT_LOG;

/***********************************************************
 *                      Local variables
 ***********************************************************
 */
static wfs_event_get_ifname_func wfs_event_ifname_cb;
static wfs_event_cb_func wfs_event_cb;


/***********************************************************
 *                      Global functions
 ***********************************************************
 */

void set_log_level(u32 level)
{
	log_level = level;
}


void reset_log_level(void)
{
	log_level = DEFAULT_LOG;
}


void print_log(u32 level, const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);

	if (level & log_level) {
		vprintf(fmt, ap);
		printf("\n");
		fflush(stdout);
	}

	va_end(ap);
}


void
print_hexdump(u32 level, const char *prefix, const u8 *buf, u32 len, u8 ascii)
{
	int line_len = 16;
	int cur_len = 0;
	int i = 0, j = 0;
	const u8 *pos = buf;

	if (!(level & log_level))
		return;

	if (!buf) {
		printf("%s - hexdump(len=%lu): [NULL]\n", prefix,
				(long unsigned int) len);
		return;
	}

	printf("%s - hexdump(len=%lu):\n", prefix, (long unsigned int) len);
	for (i = 0; i < len / line_len + 1;
			++i, len -= cur_len, pos += cur_len) {
		cur_len = (len < line_len) ? len : line_len;
		printf("    ");
		for (j = 0; j < cur_len; ++j)
			printf(" %02hhX", pos[j]);
		for (j = cur_len; j < line_len; ++j)
			printf("   ");
		printf("    ");
		if (ascii) {
			for (j = 0; j < cur_len; ++j) {
				if (isprint(pos[j]))
					printf("%c", pos[j]);
				else
					printf("_");
			}
			for (j = cur_len; j < line_len; ++j)
				printf(" ");
		}
		printf("\n");
	}
}


void wfs_event_register_ifname_cb(wfs_event_get_ifname_func func)
{
	wfs_event_ifname_cb = func;
}


void wfs_event_register_cb(wfs_event_cb_func func)
{
	wfs_event_cb = func;
}


void wfs_event(void *ctx, u32 level, const char *fmt, ...)
{
	va_list ap;
	char buf[EVT_BUF_LEN];
	char prefix[IFNAMSIZ + 3];
	int len = 0;

	memset(buf, 0, sizeof(buf));
	memset(prefix, 0, sizeof(prefix));

	va_start(ap, fmt);
	if (wfs_event_ifname_cb) {
		const char *ifname = wfs_event_ifname_cb(ctx);
		int ret = snprintf(prefix, sizeof(prefix) - 1, "%s: ", ifname);
		if (ret < 0)
			prefix[0] = 0;
	}
	len = vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
	va_end(ap);

	print_log(level, "%s%s", prefix, buf);

	if (wfs_event_cb)
		wfs_event_cb(ctx, level, buf, len);
}


void print_line(u32 level, const char *prefix, char ch)
{
#define LINE_WIDTH 80
	char line[LINE_WIDTH + 1];
	u32 prefix_len = 0;

	assert(prefix);

	prefix_len = strlen(prefix);
	if (prefix_len >= LINE_WIDTH)
		return;

	strncpy(line, prefix, prefix_len);

	memset(line + prefix_len, ch, LINE_WIDTH - prefix_len);
	line[LINE_WIDTH] = '\0';

	print_log(level, "%s", line);
}
